package com.wngbms;

import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.ByteBufFlux;
//import reactor.netty.ChannelPipelineConfigurer;
import reactor.netty.ConnectionObserver;
import reactor.netty.DisposableServer;
import reactor.netty.http.client.HttpClient;
import reactor.netty.http.server.HttpServer;
import reactor.netty.tcp.TcpServer;
//import reactor.netty.tcp.TcpServerConfig;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class ReactorNettyDemo {

    public static void main(String[] args) {
//        m1();
//        m2();
//        m3();
//        m4();
//        m5();
//        m6();
//        m7();

        Map<ChannelOption<?>, Boolean> childOptions = new HashMap<>();
        childOptions.put(ChannelOption.AUTO_READ, false);
        childOptions.put(ChannelOption.TCP_NODELAY, true);
//        TcpServerConfig config = new TcpServerConfig(
//                Collections.singletonMap(ChannelOption.SO_REUSEADDR, true),
//                childOptions,
//                () -> new InetSocketAddress(8090));

        DisposableServer server = TcpServer.create()
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
                .wiretap(true)
                .host("localhost")
                .port(8090)
                .bindNow();

        server.onDispose().block();
    }

    private static void m7() {
     /*   DisposableServer server = TcpServer
                .create()
                .doOnConnection(connection -> {
                    log.info("connected {}", connection);
                })
                .doOnChannelInit((connectionObserver, channel, remoteAddress) -> {
                    log.info("channel init {} {} {}", connectionObserver, channel, remoteAddress);
                })
                .host("localhost")
                .port(8090)
                .bindNow();

        server.onDispose().block();*/
    }

    private static void m6() {
        DisposableServer server = TcpServer.create()
                .handle((inbound, outbound) -> inbound.receive().then().log("receive data"))
                .host("localhost")
                .port(8090)
                .bindNow();

        server.onDispose().block();
    }

    private static void m5() {
        DisposableServer server = TcpServer.create()
                .handle((inbound, outbound) -> outbound.sendString(Mono.just("hello")))
                .host("localhost")
                .port(8090)
                .bindNow();

        server.onDispose()
                .block();
    }

    private static void m4() {
/*        TcpServer server = TcpServer.create()
                .handle((inbound, outbound) -> inbound.receive().then());
        server.warmup()
                .block();

        DisposableServer disposableServer = server
                .host("localhost")
                .port(8090)
                .bindNow();
        disposableServer
                .onDispose().block();*/
    }

    private static void m3() {
        TcpServer tcpServer = TcpServer.create();
        DisposableServer server1 = tcpServer
                .host("localhost")
                .port(8090)
                .bindNow();

        DisposableServer server2 = tcpServer
                .host("localhost")
                .port(8091)
                .bindNow();

        Mono.when(server1.onDispose(), server2.onDispose())
                .block();
    }

    private static void m2() {
        DisposableServer server = TcpServer
                .create()
                .host("localhost")
                .port(8090)
                .bindNow();

        server.onDispose().block();
    }

    private static void m1() {
        HttpServer
                .create()
                .port(8090)
                .route(routes -> routes.post("/test/{param}", (request, response) -> {
                    return response.sendString(request.receive()
                            .asString()
                            .map(s -> s + " " + request.param("param") + "!")
                            .log("http-server"));
                }))
                .bindNow();


        HttpClient.create()             // Prepares an HTTP client ready for configuration
                .port(8090)  // Obtains the server's port and provides it as a port to which this
                // client should connect
                .post()               // Specifies that POST method will be used
                .uri("/test/windows11")   // Specifies the path
                .send(ByteBufFlux.fromString(Flux.just("wngbms")))  // Sends the request body
                .responseContent()    // Receives the response body
                .aggregate()
                .asString()
                .log("http-client")
                .block();
    }

}
